<?php declare(strict_types=1);

namespace App\Service;

use App\Constants\ErrorCode;
use App\Exception\BusinessException;
use App\Helper\DbConfigHelper;
use App\Helper\RespHelper;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpMessage\Upload\UploadedFile;
use Hyperf\Stringable\Str;
use League\Flysystem\Filesystem;
use League\Flysystem\FilesystemException;

class FileHandler
{

    #[Inject]
    protected Filesystem $filesystem;

    public function receiveFile(UploadedFile $file, string $folder): array
    {
        [, $fileExtension] = explode('/', $file->getMimeType());
        $filePath = $this->getUploadPath($fileExtension, $folder);
        try {
            $stream = fopen($file->getRealPath(), 'r+');
            $this->filesystem->writeStream(ltrim($filePath, '/'), $stream);
            is_resource($stream) && fclose($stream);
        } catch (FilesystemException $e) {
            return RespHelper::error('文件接收错误', ['error' => $e->getMessage()]);
        }
        return RespHelper::success(['ext' => $fileExtension, 'path' => $filePath, 'full_path' => self::getFullUrl($filePath)]);
    }

    public function uploadBase64Image(string $base63String, string $folder = 'image'): array
    {
        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base63String, $result)) {
            $fileExtension = $result[2];
            $filePath = $this->getUploadPath($fileExtension, $folder);
            try {
                $this->filesystem->write($filePath, base64_decode(str_replace($result[1], '', $base63String)));
                return RespHelper::success(['ext' => $fileExtension, 'path' => $filePath, 'full_path' => self::getFullUrl($filePath)]);
            } catch (FilesystemException $e) {
                return RespHelper::error('文件接收错误', ['error' => $e->getMessage()]);
            }
        }
        return RespHelper::error('图片信息无法识别');
    }

    public function saveBuffer(string $buffer, string $savePath): array
    {
        try {
            $this->filesystem->write($savePath, $buffer);
            return RespHelper::success(['path' => $savePath, 'full_path' => self::getFullUrl($savePath)]);
        } catch (FilesystemException $e) {
            return RespHelper::error('文件接收错误', ['error' => $e->getMessage()]);
        }
    }

    /**
     * 复制文件到文件系统内
     * @param string $savePath
     * @param string $fileUrl
     * @return array
     */
    public function copyUrlFile(string $fileUrl, string $savePath): array
    {
        $content = file_get_contents($fileUrl);
        if (is_string($content)) {
            $fileAbout = explode('.', $savePath);
            $extension = $fileAbout[count($fileAbout) - 1];
            try {
                $this->filesystem->write($savePath, $content);
                return RespHelper::success(['ext' => $extension, 'path' => $savePath, 'full_path' => self::getFullUrl($savePath)]);
            } catch (FilesystemException $e) {
                return RespHelper::error('文件接收错误', ['error' => $e->getMessage()]);
            }
        }
        return RespHelper::error('操作失败，文件信息无法获取');
    }

    /**
     * 删除文件
     * @param string $filePath
     * @return bool
     */
    public function deleteFile(string $filePath): bool
    {
        $filePath = ltrim(self::clearDomain($filePath), '/');
        IS_PROD || stdPrinter()->info("删除OSS文件: " . $filePath);
        try {
            if ($this->filesystem->fileExists($filePath)) {
                $this->filesystem->delete($filePath);
                IS_PROD || stdPrinter()->info("删除OSS文件: SUCCESS");
            }
            return true;
        } catch (\Throwable $throwable) {
            IS_PROD || stdPrinter()->info("删除OSS文件: FAILURE______" . $throwable->getMessage());
            getLogger()->error("删除OSS文件: {$filePath}-FAILURE, ErrMsg_" . $throwable->getMessage());
            return false;
        }
    }

    public function getUploadPath(string $fileExtension, string $business): string
    {
        $business = trim($business);
        empty($business) && $business = 'image';
        $urlPrefix = $this->getUrlPrefix();
        $folder = "{$urlPrefix}/{$business}s/" . date('Ymd');
        $fileName = uniqid(Str::random(12)) . '.' . $fileExtension;
        return $folder . DIRECTORY_SEPARATOR . $fileName;
    }


    public function getUrlPrefix(): string
    {
        $storage_prefix = trim(env('FILE_STORAGE_PREFIX', ''));
        // 增加环境二级存储前缀
        $env_prefix = IS_PROD ? 'iss' : 'dev';
        if (empty($storage_prefix))
            $storage_prefix = '/' . $env_prefix;
        else
            $storage_prefix = '/' . trim($storage_prefix, '/') . '/' . $env_prefix;
        return $storage_prefix;
    }

    public static function getFullUrl(string $file, string $fileDomain = null): string
    {
        if (empty($file) || str_starts_with($file, 'http')) {
            return $file;
        }
        if (empty($fileDomain)) {
            $fileDomain = DbConfigHelper::instance()->getValue('FILE_DOMAIN');
        }
        if (empty($fileDomain)) {
            throw new BusinessException(ErrorCode::ERR_SERVER, "服务端配置缺失：file-d");
        }
        return rtrim($fileDomain, '/') . '/' . ltrim($file, '/');
    }

    public static function clearDomain(string $file, string $fileDomain = null): string
    {
        if (empty($file) || !str_starts_with($file, 'http')) {
            return $file;
        }
        if (empty($fileDomain)) {
            $fileDomain = DbConfigHelper::instance()->getValue('FILE_DOMAIN');
        }
        if (empty($fileDomain)) {
            throw new BusinessException(ErrorCode::ERR_SERVER, "服务端配置缺失：file-d");
        }
        return str_replace(rtrim($fileDomain, '/'), '', $file);
    }

}